| @@ -31,10 +31,10 @@ def member(request): | ||
| 31 | 31 |      rights = RightInfo.objects.filter(status=True).order_by('position') | 
| 32 | 32 | rights = [right.data for right in rights] | 
| 33 | 33 |  | 
| 34 | -    goods = GoodsInfo.objects.filter(only_for_member=False, status=True).order_by('position') | |
| 34 | +    goods = GoodsInfo.objects.filter(only_for_member=False, left_num__gt=0, status=True).order_by('position') | |
| 35 | 35 | goods = [good.data(user_id) for good in goods][:2] | 
| 36 | 36 |  | 
| 37 | -    member_goods = GoodsInfo.objects.filter(only_for_member=True, minlevel__lte=user.level, status=True).order_by('position') | |
| 37 | +    member_goods = GoodsInfo.objects.filter(only_for_member=True, left_num__gt=0, minlevel__lte=user.level, status=True).order_by('position') | |
| 38 | 38 | member_goods = [good.data(user_id) for good in member_goods] | 
| 39 | 39 | member_goods = [good for good in member_goods if not good['has_member_exchange']] | 
| 40 | 40 |  | 
| @@ -106,7 +106,7 @@ def goods(request): | ||
| 106 | 106 | except UserInfo.DoesNotExist: | 
| 107 | 107 | return response(UserStatusCode.USER_NOT_FOUND) | 
| 108 | 108 |  | 
| 109 | -    raw_goods = GoodsInfo.objects.filter(only_for_member=False, status=True).order_by('position') | |
| 109 | +    raw_goods = GoodsInfo.objects.filter(only_for_member=False, left_num__gt=0, status=True).order_by('position') | |
| 110 | 110 | banners = goods = [] | 
| 111 | 111 | for good in raw_goods: | 
| 112 | 112 | if good.is_slider: | 
| @@ -173,7 +173,7 @@ def good_exchange(request): | ||
| 173 | 173 | return response(UserStatusCode.USER_NOT_FOUND) | 
| 174 | 174 |  | 
| 175 | 175 | try: | 
| 176 | - good = GoodsInfo.objects.get(good_id=good_id) | |
| 176 | + good = GoodsInfo.objects.select_for_update().get(good_id=good_id) | |
| 177 | 177 | except GoodsInfo.DoesNotExist: | 
| 178 | 178 | return response(MemberGoodStatusCode.GOOD_NOT_FOUND) | 
| 179 | 179 |  | 
| @@ -186,6 +186,9 @@ def good_exchange(request): | ||
| 186 | 186 | user.integral -= good.integral | 
| 187 | 187 | user.save() | 
| 188 | 188 |  | 
| 189 | + good.left_num -= 1 | |
| 190 | + good.save() | |
| 191 | + | |
| 189 | 192 | GoodsOrderInfo.objects.create( | 
| 190 | 193 | user_id=user_id, | 
| 191 | 194 | good_id=good_id, | 
| @@ -0,0 +1,25 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | +# Generated by Django 1.11.26 on 2019-12-21 12:58 | |
| 3 | +from __future__ import unicode_literals | |
| 4 | + | |
| 5 | +from django.db import migrations, models | |
| 6 | + | |
| 7 | + | |
| 8 | +class Migration(migrations.Migration): | |
| 9 | + | |
| 10 | + dependencies = [ | |
| 11 | +        ('member', '0014_auto_20191221_1613'), | |
| 12 | + ] | |
| 13 | + | |
| 14 | + operations = [ | |
| 15 | + migrations.AlterField( | |
| 16 | + model_name='goodsinfo', | |
| 17 | + name='left_num', | |
| 18 | + field=models.IntegerField(db_index=True, default=0, help_text='\u5546\u54c1\u5e93\u5b58', verbose_name='left_num'), | |
| 19 | + ), | |
| 20 | + migrations.AlterField( | |
| 21 | + model_name='goodsinfo', | |
| 22 | + name='minlevel', | |
| 23 | + field=models.IntegerField(db_index=True, default=0, help_text='\u5151\u6362\u6700\u4f4e\u4f1a\u5458\u7ea7\u522b', verbose_name='minlevel'), | |
| 24 | + ), | |
| 25 | + ] | 
| @@ -28,7 +28,7 @@ class GoodsInfo(BaseModelMixin): | ||
| 28 | 28 | title = models.CharField(_(u'title'), max_length=255, blank=True, null=True, help_text=u'商品名称') | 
| 29 | 29 | desc = RichTextField(_(u'desc'), blank=True, null=True, help_text=u'商品描述') | 
| 30 | 30 | value = models.IntegerField(_(u'value'), default=99999, help_text=u'商品价值,单位分') | 
| 31 | - left_num = models.IntegerField(_(u'left_num'), default=0, help_text=u'商品库存') | |
| 31 | + left_num = models.IntegerField(_(u'left_num'), default=0, help_text=u'商品库存', db_index=True) | |
| 32 | 32 |  | 
| 33 | 33 | image = models.ImageField(_(u'image'), upload_to=upload_path, blank=True, null=True, help_text=u'商品图片') | 
| 34 | 34 |  | 
| @@ -40,7 +40,7 @@ class GoodsInfo(BaseModelMixin): | ||
| 40 | 40 | integral = models.IntegerField(_(u'integral'), default=99999, help_text=u'兑换所需积分') | 
| 41 | 41 | fee = models.IntegerField(_(u'fee'), default=99999, help_text=u'兑换需额外支付金额,单位分') | 
| 42 | 42 |  | 
| 43 | - minlevel = models.IntegerField(_(u'minlevel'), default=0, help_text=u'兑换最低会员级别') | |
| 43 | + minlevel = models.IntegerField(_(u'minlevel'), default=0, help_text=u'兑换最低会员级别', db_index=True) | |
| 44 | 44 |  | 
| 45 | 45 | only_for_member = models.BooleanField(_(u'only_for_member'), default=False, help_text=u'会员专属', db_index=True) | 
| 46 | 46 |  |